
package edu.hm.devcamp.communication;

import java.io.IOException;
import java.net.URL;
import java.util.List;

import android.app.IntentService;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.ConnectivityManager;
import android.os.Binder;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;
import edu.hm.devcamp.communication.json.JsonParser;
import edu.hm.devcamp.presentation.NetworkListener;
import edu.hm.devcamp.presentation.activities.PoiMap;
import edu.hm.devcamp.providers.Poi;
import edu.hm.devcamp.providers.PoiProviderRequest;

public class GetService extends IntentService {

    private static String sUrl = "http://munichpoi.appspot.com/api/poi/all/all";

    private NetworkListener mListener;

    private boolean mInitial;

    private boolean mConnectionNeeded = false;

    private final IBinder mBinder = new LocalBinder();

    public class LocalBinder extends Binder {
        public GetService getService() {
            return GetService.this;
        }
    }

    public GetService() {
        super("GetService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        mInitial = intent.getBooleanExtra("initial", false);
        // this needs to be executes here for the parallel processing
        handleCommand();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    private void handleCommand() {

        // update once a day
        final SharedPreferences sharedPreferences = PreferenceManager
                .getDefaultSharedPreferences(this);
        final Editor editor = sharedPreferences.edit();

        final long day = 60l * 60l * 24l * 1000l;
        final long now = System.currentTimeMillis();

        if (mInitial || (now - sharedPreferences.getLong("lastUpdate", 99999999999l) > day)) {

            // listen to connectivity changes (dynamic broadcast receiver: only
            // called when the service is active)
            BroadcastReceiver connectivityReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
                        showNoDataOnUiThread();
                    }
                }
            };

            // the intent filter
            IntentFilter connectivityFilter = new IntentFilter();
            connectivityFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);

            // check the current network connection
            final ConnectivityManager manager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);

            List<Poi> returnList = null;

            if (manager != null && manager.getActiveNetworkInfo() != null
                    && manager.getActiveNetworkInfo().isConnectedOrConnecting()) {

                try {
                    // register the broadcast receiver
                    this.registerReceiver(connectivityReceiver, connectivityFilter);

                    // time measurement
                    final long start = System.currentTimeMillis();

                    returnList = JsonParser.parseList(new URL(sUrl).openStream());

                    if (PoiMap.LOG_D) {
                        Log.d("CommunicationService",
                                "Received and parsed Data in "
                                        + (System.currentTimeMillis() - start) / 1000f + " seconds");
                    }

                    // no network connection required anymore: unregister the
                    // broadcast receiver.
                    this.unregisterReceiver(connectivityReceiver);
                }
                // might occur when the network connection is lost during the
                // request of the data
                catch (NullPointerException e) {
                    showNoDataOnUiThread();
                } catch (IOException e) {
                    Log.e("CommunicationService", "Error while requesting data", e);
                }
            } else {
                showNoDataOnUiThread();

                if (PoiMap.LOG_D) {
                    Log.d("CommunicationService", "No network connectivity!");
                }
            }

            // insert into the database.
            // here no network connectivity is needed anymore.
            if (returnList != null) {
                PoiProviderRequest.insertList(this, returnList);
            }

            if (PoiMap.LOG_D) {
                Log.d("CommunicationService", "Completed update");
            }

            editor.putLong("lastUpdate", now);
            editor.commit();
        }
    }

    private void showNoDataOnUiThread() {
        Log.d("CommunicationService", "No data connection");
        if (mListener != null) {
            mListener.noDataConnection();
        } else {
            if (PoiMap.LOG_D) {
                Log.d("CommunicationService", "No data connection and no listener registered");
            }
        }
    }

    public void setListener(NetworkListener listener) {
        mListener = listener;
    }
}
